package com.ssy.lingxi.marketing.serviceimpl.component.activity;


import cn.hutool.core.collection.CollectionUtil;
import com.ssy.lingxi.common.constant.marketing.ActivityTypeEnum;
import com.ssy.lingxi.common.constant.marketing.MerchantCouponTypeEnum;
import com.ssy.lingxi.common.constant.product.PriceTypeEnum;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.marketing.entity.activity.ActivityGoodsCouponDO;
import com.ssy.lingxi.marketing.entity.activity.ActivityGoodsDO;
import com.ssy.lingxi.marketing.entity.activity.ActivityGoodsSubsidiaryDO;
import com.ssy.lingxi.marketing.entity.coupon.MerchantCouponDO;
import com.ssy.lingxi.marketing.model.bo.*;
import com.ssy.lingxi.marketing.model.constant.MerchantCouponEffectiveTypeEnum;
import com.ssy.lingxi.marketing.model.constant.MerchantCouponGetWayEnum;
import com.ssy.lingxi.marketing.model.vo.activity.request.ActivityGoodsCouponGroupReq;
import com.ssy.lingxi.marketing.model.vo.activity.request.ActivityGoodsSubsidiaryGroupReq;
import com.ssy.lingxi.marketing.repository.ActivityGoodsCouponRepository;
import com.ssy.lingxi.marketing.repository.ActivityGoodsRepository;
import com.ssy.lingxi.marketing.repository.ActivityGoodsSubsidiaryRepository;
import com.ssy.lingxi.marketing.repository.MerchantCouponRepository;
import com.ssy.lingxi.marketing.service.ICouponReceiveService;
import com.ssy.lingxi.search.api.feign.ITemplateFeign;
import com.ssy.lingxi.search.api.model.request.TemplateCommoditySearchRequest;
import com.ssy.lingxi.search.api.model.response.CommoditySearchResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

/**
 * 活动商品数据处理组件
 * @author yzc
 * @version 2.0.0
 * @date 2021/9/25
 */
@Slf4j
@Component
public class ActivityGoodsHandleComponent {

    @Resource
    private ActivityGoodsSubsidiaryRepository goodsSubsidiaryRepository;
    @Resource
    private ActivityGoodsCouponRepository goodsCouponRepository;
    @Resource
    private MerchantCouponRepository merchantCouponRepository;
    @Resource
    private ActivityGoodsRepository activityGoodsRepository;
    @Resource
    private ICouponReceiveService couponReceiveService;
    @Resource
    private ITemplateFeign templateFeign;

    /**
     * 获取活动商品赠品Map
     *
     * @param activityGoodsIds 活动商品id
     * @return 返回结果
     */
    public Map<Long, List<ActivityGoodsSubsidiaryGroupBO>> getActivityGoodsSubsidiaryListMap(List<Long> activityGoodsIds) {
        // 查询所有活动商品的附属商品
        List<ActivityGoodsSubsidiaryDO> goodsSubList = goodsSubsidiaryRepository.findByActivityGoodsIdIn(activityGoodsIds);

        // 根据活动商品分组
        // activityGoodsId - List<ActivityGoodsSubsidiaryDO>
        Map<Long, List<ActivityGoodsSubsidiaryDO>> goodsSubMap = goodsSubList.stream().collect(Collectors.groupingBy(e -> e.getActivityGoods().getId()));

        // 遍历
        return goodsSubMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> this.groupingGoodsSubsidiary(entry.getValue())));
    }

    /**
     * 获取活动商品赠品组
     *
     * @param activityGoodsId 活动商品id
     * @return 返回结果
     */
    public List<ActivityGoodsSubsidiaryDO> getActivityGoodsSubsidiaryList(Long activityGoodsId) {
        // 查询所有活动商品的附属商品
        return goodsSubsidiaryRepository.findByActivityGoodsId(activityGoodsId);
    }

    /**
     * 获取活动商品赠品组
     *
     * @param activityGoodsId 活动商品id
     * @return 返回结果
     */
    public List<ActivityGoodsSubsidiaryGroupBO> getActivityGoodsSubsidiaryGroupList(Long activityGoodsId) {
        // 查询所有活动商品的附属商品
        List<ActivityGoodsSubsidiaryDO> goodsSubList = this.getActivityGoodsSubsidiaryList(activityGoodsId);
        return this.groupingGoodsSubsidiary(goodsSubList);
    }

    /**
     * 获取活动商品优惠券Map
     *
     * @param activityGoodsIds 活动商品id
     * @return 返回结果
     */
    public Map<Long, List<ActivityGoodsCouponGroupBO>> getActivityGoodsCouponListMap(List<Long> activityGoodsIds) {
        // 查询所有活动商品的附属优惠券
        List<ActivityGoodsCouponDO> goodsCouponDOList = goodsCouponRepository.findByActivityGoodsIdIn(activityGoodsIds);

        // activityGoodsId - List<ActivityGoodsCouponDO>
        Map<Long, List<ActivityGoodsCouponDO>> goodsCouponMap = goodsCouponDOList.stream().collect(Collectors.groupingBy(e -> e.getActivityGoods().getId()));

        return goodsCouponMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> this.groupingGoodsCoupon(entry.getValue())));
    }

    /**
     * 获取活动商品优惠券组
     *
     * @param activityGoodsId 活动商品id
     * @return 返回结果
     */
    public List<ActivityGoodsCouponGroupBO> getActivityGoodsCouponGroupList(Long activityGoodsId) {
        // 查询所有活动商品的附属优惠券
        List<ActivityGoodsCouponDO> activityGoodsCouponDO = goodsCouponRepository.findByActivityGoodsId(activityGoodsId);
        return this.groupingGoodsCoupon(activityGoodsCouponDO);
    }

    /**
     * 平铺每组赠品商品
     *            |   subsidiary_1                | groupNo_1  subsidiary_1
     * groupNo_1 -|   subsidiary_2      ====>     | groupNo_1  subsidiary_2
     *                                            |
     * groupNo_2 -|   subsidiary_3                | groupNo_2  subsidiary_3
     * @param activityType             活动类型
     * @param goodsSubsidiaryGroupList 附赠优惠券
     * @return 返回结果
     */
    public List<PfActivitySignUpGoodsSubsidiaryBO> flatGoodsSubsidiary(Integer activityType, List<ActivityGoodsSubsidiaryGroupReq> goodsSubsidiaryGroupList) {
        List<PfActivitySignUpGoodsSubsidiaryBO> goodsSubsidiaryList = new ArrayList<>();
        // 判断是否包含附属信息(赠送促销、换购、套餐)
        if (ActivityTypeEnum.containSubsidiary(activityType) && CollectionUtil.isNotEmpty(goodsSubsidiaryGroupList)) {
            // 循环平铺数据
            goodsSubsidiaryList = goodsSubsidiaryGroupList.stream().flatMap(group ->
                    group.getList().stream().map(a -> {
                        PfActivitySignUpGoodsSubsidiaryBO req = new PfActivitySignUpGoodsSubsidiaryBO();
                        req.setId(a.getId());
                        req.setProductId(a.getProductId());
                        req.setSkuId(a.getSkuId());
                        req.setProductName(a.getProductName());
                        req.setCategory(a.getCategory());
                        req.setBrand(a.getBrand());
                        req.setUnit(a.getUnit());
                        req.setPrice(a.getPrice());
                        req.setSwapPrice(a.getSwapPrice());
                        req.setNum(a.getNum());
                        req.setProductImgUrl(a.getProductImgUrl());
                        req.setGroupNo(group.getGroupNo());
                        req.setGroupPrice(group.getGroupPrice());
                        req.setLimitValue(group.getLimitValue());
                        return req;
                    })
            ).collect(Collectors.toList());
        }

        return goodsSubsidiaryList;
    }

    /**
     * 平铺每组赠品优惠券
     *            |   coupon_1                | groupNo_1  coupon_1
     * groupNo_1 -|   coupon_2      ====>     | groupNo_1  coupon_2
     *                                        |
     * groupNo_2 -|   coupon_3                | groupNo_2  coupon_3
     * @param activityType    活动类型
     * @param couponGroupList 附赠优惠券
     * @return 返回结果
     */
    public List<PfActivitySignUpGoodsCouponBO> flatGoodsCoupon(Integer activityType, List<ActivityGoodsCouponGroupReq> couponGroupList) {
        List<PfActivitySignUpGoodsCouponBO> GoodsCouponList = new ArrayList<>();
        // 判断是否包含附属信息(赠送促销、换购、套餐)
        if (ActivityTypeEnum.containSubsidiary(activityType) && CollectionUtil.isNotEmpty(couponGroupList)) {
            // 循环平铺数据
            GoodsCouponList = couponGroupList.stream().flatMap(group ->
                    group.getList().stream().map(a -> {
                        PfActivitySignUpGoodsCouponBO req = new PfActivitySignUpGoodsCouponBO();
                        req.setId(a.getId());
                        req.setActivityGoodsId(a.getActivityGoodsId());
                        req.setCouponId(a.getCouponId());
                        req.setCouponName(a.getCouponName());
                        req.setNum(a.getNum());
                        req.setGroupNo(group.getGroupNo());
                        req.setLimitValue(group.getLimitValue());
                        return req;
                    })
            ).collect(Collectors.toList());
        }

        return GoodsCouponList;
    }

    /**
     * 赠品商品按组号分组
     * | groupNo_1  subsidiary_1                         |   subsidiary_1
     * | groupNo_1  subsidiary_2     ====>    groupNo_1 -|   subsidiary_2
     * |
     * | groupNo_2  subsidiary_3              groupNo_2 -|   subsidiary_3
     * @param subsidiaryDOList 赠品商品集合
     * @return 返回结果
     */
    public List<ActivityGoodsSubsidiaryGroupBO> groupingGoodsSubsidiary(List<ActivityGoodsSubsidiaryDO> subsidiaryDOList) {
        // 附属商品按groupNo分组
        // groupNo - List<ActivityGoodsSubsidiaryDO>
        Map<Integer, List<ActivityGoodsSubsidiaryDO>> groupNoSubsidiaryDOMap = subsidiaryDOList.stream().collect(Collectors.groupingBy(ActivityGoodsSubsidiaryDO::getGroupNo));

        List<ActivityGoodsSubsidiaryGroupBO> groupBOList = groupNoSubsidiaryDOMap.entrySet().stream().map(groupNoEntry -> {
            ActivityGoodsSubsidiaryGroupBO resp = new ActivityGoodsSubsidiaryGroupBO();
            Integer groupNo = groupNoEntry.getKey();
            List<ActivityGoodsSubsidiaryDO> groupNoSubsidiaryDoList = groupNoEntry.getValue();
            // 获取冗余的组号,门槛值,套餐价格
            ActivityGoodsSubsidiaryDO activityGoodsSubsidiaryDO = Optional.ofNullable(groupNoSubsidiaryDoList.get(0)).orElse(new ActivityGoodsSubsidiaryDO());
            resp.setGroupPrice(activityGoodsSubsidiaryDO.getGroupPrice());
            resp.setLimitValue(activityGoodsSubsidiaryDO.getLimitValue());
            resp.setGroupNo(groupNo);

            // 处理每一组的附属商品
            List<ActivityGoodsSubsidiaryGroupDetailBO> groupDetailsReqList = groupNoSubsidiaryDoList.stream().map(e -> {
                ActivityGoodsSubsidiaryGroupDetailBO detail = new ActivityGoodsSubsidiaryGroupDetailBO();
                detail.setId(e.getId());
                detail.setProductId(e.getProductId());
                detail.setSkuId(e.getSkuId());
                detail.setProductName(e.getProductName());
                detail.setCategory(e.getCategory());
                detail.setBrand(e.getBrand());
                detail.setUnit(e.getUnit());
                detail.setPrice(e.getPrice());
                detail.setSwapPrice(e.getSwapPrice());
                detail.setNum(e.getNum());
                detail.setProductImgUrl(e.getProductImgUrl());
                return detail;
            }).collect(Collectors.toList());

            resp.setList(groupDetailsReqList);
            return resp;
        }).collect(Collectors.toList());

        return groupBOList;
    }

    /**
     * 赠品优惠券按组号分组
     * | groupNo_1  coupon_1                         |   coupon_1
     * | groupNo_1  coupon_2     ====>    groupNo_1 -|   coupon_2
     * |
     * | groupNo_2  coupon_3              groupNo_2 -|   coupon_3
     * @param couponDOList 赠品优惠券集合
     * @return 返回结果
     */
    public List<ActivityGoodsCouponGroupBO> groupingGoodsCoupon(List<ActivityGoodsCouponDO> couponDOList) {
        // 查询赠送商家优惠券信息
        List<Long> couponIdList = couponDOList.stream().map(ActivityGoodsCouponDO::getCouponId).collect(Collectors.toList());
        // couponId - MerchantCouponDO
        Map<Long, MerchantCouponDO> couponDOMap = merchantCouponRepository.findAllById(couponIdList).stream().collect(Collectors.toMap(MerchantCouponDO::getId, e -> e));

        // groupNo - List<ActivityGoodsCouponDO>
        Map<Integer, List<ActivityGoodsCouponDO>> groupNoCouponDOMap = couponDOList.stream().collect(Collectors.groupingBy(ActivityGoodsCouponDO::getGroupNo));

        List<ActivityGoodsCouponGroupBO> groupBOList = groupNoCouponDOMap.entrySet().stream().flatMap(groupNoEntry -> {
            Integer groupNo = groupNoEntry.getKey();
            List<ActivityGoodsCouponDO> groupNoCouponDOList = groupNoEntry.getValue();

            return groupNoCouponDOList.stream().map(e -> {
                ActivityGoodsCouponDO activityGoodsCouponDO = Optional.ofNullable(groupNoCouponDOList.get(0)).orElse(new ActivityGoodsCouponDO());

                List<ActivityGoodsCouponGroupDetailBO> groupDetailsReqList = groupNoCouponDOList.stream().map(a -> {
                    ActivityGoodsCouponGroupDetailBO detailsReq = new ActivityGoodsCouponGroupDetailBO();
                    detailsReq.setId(a.getId());
                    detailsReq.setActivityGoodsId(a.getActivityGoods().getId());
                    detailsReq.setNum(a.getNum());
                    detailsReq.setCouponId(a.getCouponId());
                    MerchantCouponDO merchantCouponDO = Optional.ofNullable(couponDOMap.get(a.getCouponId())).orElse(new MerchantCouponDO());
                    detailsReq.setCouponName(merchantCouponDO.getName());
                    detailsReq.setType(merchantCouponDO.getType());
                    detailsReq.setTypeName(MerchantCouponTypeEnum.getCodeMessage(merchantCouponDO.getType()));
                    detailsReq.setDenomination(merchantCouponDO.getDenomination());
                    detailsReq.setGetWay(merchantCouponDO.getGetWay());
                    detailsReq.setGetWayName(MerchantCouponGetWayEnum.getCodeMessage(merchantCouponDO.getGetWay()));
                    detailsReq.setUseConditionMoney(merchantCouponDO.getUseConditionMoney());
                    detailsReq.setEffectiveType(merchantCouponDO.getEffectiveType());
                    detailsReq.setEffectiveTypeName(MerchantCouponEffectiveTypeEnum.getCodeMessage(merchantCouponDO.getEffectiveType()));
                    detailsReq.setEffectiveTimeStart(merchantCouponDO.getEffectiveTimeStart());
                    detailsReq.setEffectiveTimeEnd(merchantCouponDO.getEffectiveTimeEnd());
                    detailsReq.setInvalidDay(merchantCouponDO.getInvalidDay());
                    return detailsReq;
                }).collect(Collectors.toList());

                ActivityGoodsCouponGroupBO resp = new ActivityGoodsCouponGroupBO();
                resp.setGroupNo(groupNo);
                resp.setLimitValue(activityGoodsCouponDO.getLimitValue());
                resp.setList(groupDetailsReqList);
                return resp;
            });
        }).collect(Collectors.toList());

        return groupBOList;
    }

    /**
     * 根据活动ids与skuIds查询活动商品信息
     * @param activityIds
     * @param skuIds
     */
    public List<ActivityGoodsDO> getActivityGoodsRestrictNum(List<Long> activityIds,List<Long> skuIds){
        return activityGoodsRepository.findAllByActivityIdInAndSkuIdIn(activityIds, skuIds);
    }

    /**
     * 根据平台品类ID或会员品类ID获取商品ID
     * 备注: 由yzc迁移代码
     * @author fhj
     * @param categoryId 平台品类ID
     * @param customerCategoryId 会员品类ID
     * @return 商品ID集合
     * */
    public List<Long> getGoodsIdListByCategory(Long categoryId, Long customerCategoryId, Long shopId) {
        TemplateCommoditySearchRequest searchRequest = new TemplateCommoditySearchRequest();
        searchRequest.setCurrent(1);
        searchRequest.setPageSize(1000);
        searchRequest.setShopId(shopId);
        searchRequest.setCategoryId(categoryId);
        searchRequest.setCustomerCategoryId(customerCategoryId);
        searchRequest.setPriceTypeList(Stream.of(PriceTypeEnum.Cash.getCode()).collect(Collectors.toList()));
        Wrapper<PageData<CommoditySearchResponse>> wrapper = templateFeign.searchCommodityList(searchRequest);
        if (wrapper.getCode() != ResponseCode.SUCCESS.getCode()) {
            log.info("请求搜索服务失败:{}", wrapper.getMessage());
            return new ArrayList<>();
        }
        if (wrapper.getData().getTotalCount().equals(0L)) {
            return new ArrayList<>();
        }

        return wrapper.getData().getData().stream().map(CommoditySearchResponse::getId).collect(toList());
    }
}